package com.wanxi.user.service.impl;


import com.wanxi.common.entity.LoginParams;
import com.wanxi.common.entity.Permission;
import com.wanxi.common.entity.User;
import com.wanxi.common.result.CommonResult;
import com.wanxi.common.result.ResultDTO;
import com.wanxi.user.mapper.RoleMapper;
import com.wanxi.user.mapper.UserMapper;
import com.wanxi.user.service.UserService;
import com.wanxi.user.util.JwtTokenUtil;
import com.wanxi.user.util.PasswordUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
@Transactional
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper UserMapper;

    @Autowired
    private RoleMapper roleMapper;

    @Value("${jwt.tokenHead}")
    String tokenHead;

    @Autowired
    private JwtTokenUtil jwtTokenUtil;

    @Value("${jwt.expiration}")
    private Long expiration;


    @Autowired
    private RedisTemplate<String,Object> redisTemplate;




    @Override
    public User getUserByName(String name) {
        List<User> users = UserMapper.getUserByName(name);
//        Assert.isTrue(users.size() != 1,"您输入的账户不存在，或者有多个相同的账户");
        return users.get(0);
    }

    @Override
    public List<Permission> getPermissionsByUserId(Integer UserId) {
        return UserMapper.getPermissionByUserId(UserId);
    }

    @Override
    public ResultDTO login(LoginParams loginParams) {
        String code = loginParams.getCode();
        String vCode = (String) redisTemplate.opsForValue().get(loginParams.getUuid());

        if (vCode == null || !code.equals(vCode)){
          return ResultDTO.builder()
                    .code(0)
                    .msg("error-code")
                    .build();
        }

        //从redis查，没有就从数据库里查
        User user = findUserFromRedis(loginParams.getUsername());
        if(user==null){
            return ResultDTO.builder()
                    .code(0)
                    .msg("error")
                    .build();
        }

        //验证密码
        String password = loginParams.getPassword();
        boolean matches = PasswordUtils.verifyPassword(password,user.getPassword());
        if (!matches){
            return ResultDTO.builder()
                    .code(0)
                    .msg("error")
                    .build();
        }

        // 获取用户所有权限
        List<Permission> permissionsByUserId = getPermissionsByUserId(user.getId());
        // 将权限list 转化为set形式
        HashSet<Permission> wxPermissions = new HashSet<>(permissionsByUserId);
        // 将权限设置到用户实例中
        user.setAuthorities(wxPermissions);
        // 使用jwtTokenUtil 生成token

        //登录成功后缓存用户信息12小时，token为token失效时间的双倍
        String userKey = "user:" + user.getUsername();
        redisTemplate.opsForValue().set(userKey,user,12,TimeUnit.HOURS);

        HashMap<String, String> data = new HashMap<>();

        String token = jwtTokenUtil.generateToken(user);
        String tokenKey = "token:" + token;
        redisTemplate.opsForValue().set(tokenKey,token,expiration*2, TimeUnit.MILLISECONDS);

        data.put("tokenHead",tokenHead);
        data.put("access_token",token);
        // localStorage.setItem("Authorization","Bearer sdsdfdfds")
        // $ajax{data:{},type:"",header:{"Authorization":"Bearer sdsdfdfds"}}
        return ResultDTO.builder()
                .code(0)
                .msg("success")
                .data(data)
                .build();

    }


    private User findUserFromRedis(String username){
        String userKey = "user:" + username;
        User UserFromRedis = (User) redisTemplate.opsForValue().get(userKey);
        if(UserFromRedis==null){
            User User = UserMapper.findByName(username);
            redisTemplate.opsForValue().set(userKey,User,12,TimeUnit.HOURS);
            return User;
        }
        return UserFromRedis;
    }



    @Override
    public ResultDTO add(User user) {
        User userExist = UserMapper.findByName(user.getUsername());
        if (userExist != null){
            return ResultDTO.builder()
                    .code(0)
                    .msg("have same name")
                    .count(-1)
                    .data("")
                    .build();
        }else {
            String anWen = PasswordUtils.hashPassword(user.getPassword());
            user.setPassword(anWen);

            int addUserCount = UserMapper.add(user);

            String[] roleNames = user.getRole().split(",");

            Integer[] roleIds = roleMapper.findIdByName(roleNames);
//        Integer[] roleIds = Stream.of(role).map(Integer::valueOf).toArray(Integer[]::new);

            User userByName = UserMapper.findByName(user.getUsername());
//        WxUser byId = wxUserMapper.findById(byName.getId());

            Integer userId = userByName.getId();
            int addRoleCount = UserMapper.saveUserAndRole(userId, roleIds);

            return ResultDTO.builder()
                    .code(0)
                    .msg("")
                    .count(addRoleCount)
                    .data(0)
                    .build();
        }




    }

    @Override
    public CommonResult<HashMap<String,Object>> findAll(User user) {

        user.setPage((user.getPage() - 1) * user.getLimit());

        Integer count = UserMapper.count(user);
        List<User> userList = UserMapper.findAll(user);
        HashMap<String, Object> data = new HashMap<>();

        data.put("count",count);
        data.put("data",userList);
        return CommonResult.success(data);

    }

    @Override
    public ResultDTO delete(User user) {


        int deleteUserCount = UserMapper.delete(user);

        int deleteRoleCount = UserMapper.deleteUserAndRole(user);


        return ResultDTO.builder()
                .code(0)
                .msg("")
                .count(deleteRoleCount)
                .data("")
                .build();
    }

    @Override
    public ResultDTO findById(Integer id) {
   return ResultDTO.builder()
                .code(0)
                .msg("")
                .count(0)
                .data(UserMapper.findById(id))
                .build();
    }

    @Override
    public CommonResult update(User user) {
        User userExist = UserMapper.findByName(user.getUsername());
        if (userExist == null){
            return CommonResult.success(-1);
        }else {

            int addUserCount = UserMapper.update(user);

            String[] roleNames = user.getRole().split(",");

            Integer[] roleIds = roleMapper.findIdByName(roleNames);

            Integer userId = user.getId();

            int delete = UserMapper.deleteUserAndRole(user);
            int updateRoleCount = UserMapper.saveUserAndRole(userId, roleIds);
            return CommonResult.success(updateRoleCount);

        }}

    @Override
    public ResultDTO updatePassword(User user) {
        User userExist = UserMapper.findByName(user.getUsername());
        if (userExist == null){
            return ResultDTO.builder()
                    .code(0)
                    .msg("have no")
                    .count(-1)
                    .data("")
                    .build();
        }else {
            String anWen = PasswordUtils.hashPassword(user.getPassword());
            user.setPassword(anWen);
            int updatePasswordCount = UserMapper.updatePassword(user);
            return ResultDTO.builder()
                    .code(0)
                    .msg("")
                    .count(updatePasswordCount)
                    .data(0)
                    .build();
        }}

    @Override
    public CommonResult checkAccessToUri(String uri, String username) {
        User userByName = getUserByName(username);
        List<Permission> permissionsByUserId = getPermissionsByUserId(userByName.getId());
        boolean b = permissionsByUserId.stream().anyMatch(permission -> StringUtils.equals(permission.getUri(), uri));
        return b? CommonResult.success(true): CommonResult.forbidden(null);
    }

}

